namespace MyCompany.UserInterfaceLibrary {
	using System;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Controls.Primitives;
	using System.Windows.Data;
	using System.Windows.Input;
	using System.Windows.Media;

	public abstract class ToggleButtonBase : ToggleButton {
		public static readonly DependencyProperty DropDownContextMenuProperty = DependencyProperty.Register("DropDownContextMenu", typeof(object), typeof(ToggleButtonBase), new FrameworkPropertyMetadata(null));

		public static readonly DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(ImageSource), typeof(ToggleButtonBase));

		public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(UIElement), typeof(ToggleButtonBase));

		public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(ToggleButtonBase));

		public static readonly DependencyProperty ToggleButtonBaseProperty = DependencyProperty.Register("ToggleButtonBaseCommand", typeof(ICommand), typeof(ToggleButtonBase), new FrameworkPropertyMetadata(null));

		protected ToggleButtonBase() {
			// Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property
			var binding = new Binding("DropDownContextMenu.IsOpen") { Source = this };
			SetBinding(IsCheckedProperty, binding);
		}

		public object DropDownContextMenu
		{
			get
			{
				return GetValue(DropDownContextMenuProperty);
			}
			set
			{
				SetValue(DropDownContextMenuProperty, value);
			}
		}

		public ImageSource Image
		{
			get
			{
				return GetValue(ImageProperty) as ImageSource;
			}
			set
			{
				SetValue(ImageProperty, value);
			}
		}

		public UIElement Target
		{
			get
			{
				return GetValue(TargetProperty) as UIElement;
			}
			set
			{
				SetValue(TargetProperty, value);
			}
		}

		public string Text
		{
			get
			{
				return GetValue(TextProperty) as string;
			}
			set
			{
				SetValue(TextProperty, value);
			}
		}

		public ICommand ToggleButtonBaseCommand
		{
			get
			{
				return GetValue(ToggleButtonBaseProperty) as ICommand;
			}
			set
			{
				SetValue(ToggleButtonBaseProperty, value);
			}
		}

		public override void OnApplyTemplate() {
			base.OnApplyTemplate();

			UpdateState();
		}

		protected override void OnClick() {
			if (DropDownContextMenu == null) // Default behavior is to allow the control to become checked, but that doesn't work with this context menu concept.
				base.OnClick();
			else {
				if (ToggleButtonBaseCommand != null)
					ToggleButtonBaseCommand.Execute(null);
				if (DropDownContextMenu is ContextMenu) {
					// If there is a drop-down assigned to this button, then position and display it
					((ContextMenu)DropDownContextMenu).PlacementTarget = this;
					((ContextMenu)DropDownContextMenu).Placement = PlacementMode.Bottom;
					((ContextMenu)DropDownContextMenu).IsOpen = !((ContextMenu)DropDownContextMenu).IsOpen;
				}
				else if (DropDownContextMenu is Popup) {
					((Popup)DropDownContextMenu).PlacementTarget = this;
					((Popup)DropDownContextMenu).Placement = PlacementMode.Bottom;
					((Popup)DropDownContextMenu).IsOpen = !((Popup)DropDownContextMenu).IsOpen;
				}
				else
					throw new InvalidOperationException("Drop-down control must be a ContextMenu or a Popup.");
			}
		}

		protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) {
			base.OnPropertyChanged(e);

			if (e.Property == ToggleButtonBaseProperty)
				Command = ToggleButtonBaseCommand;
			else if (e.Property == IsMouseOverProperty)
				UpdateState();
			else if (e.Property == IsCheckedProperty)
				UpdateState();
			else if (e.Property == DropDownContextMenuProperty)
				IsChecked = false; // Make sure that we don't start out checked.
		}

		protected abstract void UpdateState();
	}
}
